
package com.zhrenjie04.alex.util;

import java.io.IOException;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.LinkedList;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.zhrenjie04.alex.core.User;

/**
 * @author 张人杰
 */
public class JsonUtil {

	private static final Logger logger = Logger.getLogger(JsonUtil.class);

	private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();

	static {
		OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
		OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
		OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
		OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	}

	static final String DYNC_FILTER_PK_AND_OTHERS = "DYNC_FILTER_PK_AND_OTHERS";

	@JsonFilter(DYNC_FILTER_PK_AND_OTHERS)
	interface DynamicFilterPkAndOthers {
	}

	/**
	 * 序列化（序列化过程中过滤掉指定的属性）
	 * 
	 * @param obj           需要序列化的对象
	 * @param filteredProps 需要过滤掉的属性，以“,”号隔开
	 * @return
	 */
	public static String stringifyWithout(Object obj, Class clazz, String filteredProps) {
		if (obj == null) {
			return null;
		}
		if (obj instanceof String) {
			return (String) obj;
		}
		ObjectMapper mapper = new ObjectMapper();
		SimpleFilterProvider filterProvider = new SimpleFilterProvider();
		if (filteredProps != null && !"".equals(filteredProps)) {
			filterProvider.addFilter(DYNC_FILTER_PK_AND_OTHERS,
					SimpleBeanPropertyFilter.serializeAllExcept(filteredProps.replaceAll("\\s", "").split(",")));
			mapper.addMixIn(clazz, DynamicFilterPkAndOthers.class);
		}
		mapper.setFilterProvider(filterProvider);
		try {
			return mapper.writeValueAsString(obj);
		} catch (JsonGenerationException e) {
			logger.error("encode(Object)", e);
		} catch (JsonMappingException e) {
			logger.error("encode(Object)", e);
		} catch (IOException e) {
			logger.error("encode(Object)", e);
		}
		return null;
	}

	private JsonUtil() {
		if (thisObjectMapper == null) {
			thisObjectMapper = new ObjectMapper();
		}
		if (filterProvider == null) {
			filterProvider = new SimpleFilterProvider();
		}
	}

	public static JsonUtil newSerializer() {
		return new JsonUtil();
	}

	public String doStringify(Object obj) {
		if (obj == null) {
			return null;
		}
		if (obj instanceof String) {
			return (String) obj;
		}
		try {
			return thisObjectMapper.writeValueAsString(obj);
		} catch (JsonGenerationException e) {
			logger.error("encode(Object)", e);
		} catch (JsonMappingException e) {
			logger.error("encode(Object)", e);
		} catch (IOException e) {
			logger.error("encode(Object)", e);
		}
		return null;
	}

	private ObjectMapper thisObjectMapper;
	private int filterCount = 0;
	private SimpleFilterProvider filterProvider;

	public JsonUtil without(Class tClazz, String filteredProps) {
		++filterCount;
		if (filterCount > MAX_FILTER_COUNT) {
			throw new RuntimeException("只能使用" + MAX_FILTER_COUNT + "次JsonUtil的without调用");
		}
		if (thisObjectMapper == null) {
			thisObjectMapper = new ObjectMapper();
		}
		if (filterProvider == null) {
			filterProvider = new SimpleFilterProvider();
		}
		if (filteredProps != null && !"".equals(filteredProps)) {
			filterProvider.addFilter(DYNC_FILTER_PREFIX + filterCount,
					SimpleBeanPropertyFilter.serializeAllExcept(filteredProps.replaceAll("\\s", "").split(",")));
			thisObjectMapper.addMixIn(tClazz, getFilterClass(filterCount));
		}
		thisObjectMapper.setFilterProvider(filterProvider);
		return this;
	}

	public static String stringify(Object obj) {
		if (obj == null) {
			return null;
		}
		if (obj instanceof String) {
			return (String) obj;
		}
		try {
			return OBJECT_MAPPER.writeValueAsString(obj);
		} catch (JsonGenerationException e) {
			logger.error("encode(Object)", e);
		} catch (JsonMappingException e) {
			logger.error("encode(Object)", e);
		} catch (IOException e) {
			logger.error("encode(Object)", e);
		}
		return null;
	}

	/**
	 * 将json string反序列化成对象
	 */
	public static <T> T parse(String json, Class<T> valueType) {
		if (json == null || "".equals(json)) {
			return null;
		}
		try {
			return OBJECT_MAPPER.readValue(json, valueType);
		} catch (JsonParseException e) {
			logger.error("decode(String, Class<T>)", e);
		} catch (JsonMappingException e) {
			logger.error("decode(String, Class<T>)", e);
		} catch (IOException e) {
			logger.error("decode(String, Class<T>)", e);
		}
		return null;
	}

	/**
	 * 将json array反序列化为数组
	 */
	@SuppressWarnings("unchecked")
	public static <T> T parse(String json, TypeReference<T> typeReference) {
		if (json == null || "".equals(json)) {
			return null;
		}
		try {
			return (T) OBJECT_MAPPER.readValue(json, typeReference);
		} catch (JsonParseException e) {
			logger.error("decode(String, JsonTypeReference<T>)", e);
		} catch (JsonMappingException e) {
			logger.error("decode(String, JsonTypeReference<T>)", e);
		} catch (IOException e) {
			logger.error("decode(String, JsonTypeReference<T>)", e);
		}
		return null;
	}

	public static void main(String[] args) {
		LinkedList<Integer> result = JsonUtil.parse("[1,2,3,4]", new TypeReference<LinkedList<Integer>>() {
		});
		HashMap<String, Object> map = JsonUtil.parse(
				"{\"userId\":\"111111111111111111\",\"count\":1,\"userRank\":1111111111111111111,\"userScore\":111111111111111111111.1,\"userName\":\"aaa\"}",
				new TypeReference<HashMap<String, Object>>() {
				});
		System.out.println(result.size());
		System.out.println(map.get("userRank").toString());
		System.out.println(new BigInteger(map.get("userRank").toString()).longValue());
		System.out.println(map.get("count"));
		System.out.println(map.get("count"));
		User user = new User();
		map.put("user", user);
		System.out.println(JsonUtil.newSerializer().without(User.class, "isDeleted,otherParams").doStringify(user));
	}

	static final String DYNC_FILTER_PREFIX = "DYNC_FILTER";
	static final String DYNC_FILTER1 = "DYNC_FILTER1";
	static final String DYNC_FILTER2 = "DYNC_FILTER2";
	static final String DYNC_FILTER3 = "DYNC_FILTER3";
	static final String DYNC_FILTER4 = "DYNC_FILTER4";
	static final String DYNC_FILTER5 = "DYNC_FILTER5";
	static final String DYNC_FILTER6 = "DYNC_FILTER6";
	static final String DYNC_FILTER7 = "DYNC_FILTER7";
	static final String DYNC_FILTER8 = "DYNC_FILTER8";
	static final String DYNC_FILTER9 = "DYNC_FILTER9";
	static final String DYNC_FILTER10 = "DYNC_FILTER10";
	static final String DYNC_FILTER11 = "DYNC_FILTER11";
	static final String DYNC_FILTER12 = "DYNC_FILTER12";
	static final String DYNC_FILTER13 = "DYNC_FILTER13";
	static final String DYNC_FILTER14 = "DYNC_FILTER14";
	static final String DYNC_FILTER15 = "DYNC_FILTER15";
	static final String DYNC_FILTER16 = "DYNC_FILTER16";
	static final String DYNC_FILTER17 = "DYNC_FILTER17";
	static final String DYNC_FILTER18 = "DYNC_FILTER18";
	static final String DYNC_FILTER19 = "DYNC_FILTER19";
	static final String DYNC_FILTER20 = "DYNC_FILTER20";
	static final String DYNC_FILTER21 = "DYNC_FILTER21";
	static final String DYNC_FILTER22 = "DYNC_FILTER22";
	static final String DYNC_FILTER23 = "DYNC_FILTER23";
	static final String DYNC_FILTER24 = "DYNC_FILTER24";
	static final String DYNC_FILTER25 = "DYNC_FILTER25";
	static final String DYNC_FILTER26 = "DYNC_FILTER26";
	static final String DYNC_FILTER27 = "DYNC_FILTER27";
	static final String DYNC_FILTER28 = "DYNC_FILTER28";
	static final String DYNC_FILTER29 = "DYNC_FILTER29";
	static final String DYNC_FILTER30 = "DYNC_FILTER30";
	static final int MAX_FILTER_COUNT = 30;

	@JsonFilter(DYNC_FILTER1)
	interface DynamicFilter1 {
	}

	@JsonFilter(DYNC_FILTER2)
	interface DynamicFilter2 {
	}

	@JsonFilter(DYNC_FILTER3)
	interface DynamicFilter3 {
	}

	@JsonFilter(DYNC_FILTER4)
	interface DynamicFilter4 {
	}

	@JsonFilter(DYNC_FILTER5)
	interface DynamicFilter5 {
	}

	@JsonFilter(DYNC_FILTER6)
	interface DynamicFilter6 {
	}

	@JsonFilter(DYNC_FILTER7)
	interface DynamicFilter7 {
	}

	@JsonFilter(DYNC_FILTER8)
	interface DynamicFilter8 {
	}

	@JsonFilter(DYNC_FILTER9)
	interface DynamicFilter9 {
	}

	@JsonFilter(DYNC_FILTER10)
	interface DynamicFilter10 {
	}

	@JsonFilter(DYNC_FILTER11)
	interface DynamicFilter11 {
	}

	@JsonFilter(DYNC_FILTER12)
	interface DynamicFilter12 {
	}

	@JsonFilter(DYNC_FILTER13)
	interface DynamicFilter13 {
	}

	@JsonFilter(DYNC_FILTER14)
	interface DynamicFilter14 {
	}

	@JsonFilter(DYNC_FILTER15)
	interface DynamicFilter15 {
	}

	@JsonFilter(DYNC_FILTER16)
	interface DynamicFilter16 {
	}

	@JsonFilter(DYNC_FILTER17)
	interface DynamicFilter17 {
	}

	@JsonFilter(DYNC_FILTER18)
	interface DynamicFilter18 {
	}

	@JsonFilter(DYNC_FILTER19)
	interface DynamicFilter19 {
	}

	@JsonFilter(DYNC_FILTER20)
	interface DynamicFilter20 {
	}

	@JsonFilter(DYNC_FILTER21)
	interface DynamicFilter21 {
	}

	@JsonFilter(DYNC_FILTER22)
	interface DynamicFilter22 {
	}

	@JsonFilter(DYNC_FILTER23)
	interface DynamicFilter23 {
	}

	@JsonFilter(DYNC_FILTER24)
	interface DynamicFilter24 {
	}

	@JsonFilter(DYNC_FILTER25)
	interface DynamicFilter25 {
	}

	@JsonFilter(DYNC_FILTER26)
	interface DynamicFilter26 {
	}

	@JsonFilter(DYNC_FILTER27)
	interface DynamicFilter27 {
	}

	@JsonFilter(DYNC_FILTER28)
	interface DynamicFilter28 {
	}

	@JsonFilter(DYNC_FILTER29)
	interface DynamicFilter29 {
	}

	@JsonFilter(DYNC_FILTER30)
	interface DynamicFilter30 {
	}

	@SuppressWarnings("rawtypes")
	private Class getFilterClass(int count) {
		switch (count) {
		case 1:
			return DynamicFilter1.class;
		case 2:
			return DynamicFilter2.class;
		case 3:
			return DynamicFilter3.class;
		case 4:
			return DynamicFilter4.class;
		case 5:
			return DynamicFilter5.class;
		case 6:
			return DynamicFilter6.class;
		case 7:
			return DynamicFilter7.class;
		case 8:
			return DynamicFilter8.class;
		case 9:
			return DynamicFilter9.class;
		case 10:
			return DynamicFilter10.class;
		case 11:
			return DynamicFilter11.class;
		case 12:
			return DynamicFilter12.class;
		case 13:
			return DynamicFilter13.class;
		case 14:
			return DynamicFilter14.class;
		case 15:
			return DynamicFilter15.class;
		case 16:
			return DynamicFilter16.class;
		case 17:
			return DynamicFilter17.class;
		case 18:
			return DynamicFilter18.class;
		case 19:
			return DynamicFilter19.class;
		case 20:
			return DynamicFilter20.class;
		case 21:
			return DynamicFilter21.class;
		case 22:
			return DynamicFilter22.class;
		case 23:
			return DynamicFilter23.class;
		case 24:
			return DynamicFilter24.class;
		case 25:
			return DynamicFilter25.class;
		case 26:
			return DynamicFilter26.class;
		case 27:
			return DynamicFilter27.class;
		case 28:
			return DynamicFilter28.class;
		case 29:
			return DynamicFilter29.class;
		case 30:
			return DynamicFilter30.class;
		default:
			return null;
		}
	}

}